package shovelsoft.btmetaparser;

import java.io.InputStream;

import shovelsoft.btmetaparser.structs.INode;
import shovelsoft.btmetaparser.structs.Leaf;
import shovelsoft.btmetaparser.structs.Node;
import shovelsoft.btmetaparser.tokens.IToken;
import shovelsoft.btmetaparser.tokens.ITokenParser;

/***
 * Parse a token stream ( or raw data ) into a tree structure.
 * @author Chris Stones
 *
 */
public class Parse implements ITokenParser {

	private INode root;
	private INode node;
	
	/***
	 * Parse a list of tokens.
	 * @param Tokens 
	 * @throws Exception
	 */
	public Parse(java.util.List<IToken> Tokens) throws Exception {
		
		DoParse(Tokens);
	}
	
	/***
	 * Parse raw binary encoded data ( Bit-torrent meta-file data).
	 * @param is
	 * @throws Exception
	 */
	public Parse(InputStream is) throws Exception {
		
		DoParse( new Tokenise(is).Tokens );
	}
	
	/***
	 * get tree root
	 * @return Metadata global Dictionary
	 */
	public INode getRoot() {
		
		return root;
	}
	
	/***
	 * Parse a token stream
	 * @param Tokens
	 * @throws Exception
	 */
	private void DoParse(java.util.List<IToken> Tokens) throws Exception {
				
		root = node = null;
		for(IToken Token : Tokens)
			Token.accept( this );
		
		if(node != null)
			throw new Exception("parse error: expected End token 'e'");
	}
	
	/***
	 * Visit a Dictionary struct, add it to our tree
	 * @param dictionary A Dictionary Node
	 */
	@Override
	public void visit(shovelsoft.btmetaparser.tokens.Dictionary dictionary) throws Exception {
		
		INode parent = node;
		
		node = new Node(dictionary, parent);
		
		if(root == null)
			root = node;
		
		if(parent != null)
			parent.addChild(node);
	}

	/***
	 * Visit a List struct, add it to our tree
	 * @param list A List Node
	 */
	@Override
	public void visit(shovelsoft.btmetaparser.tokens.List list) throws Exception {

		INode parent = node;
		
		node = new Node(list,node);
		
		parent.addChild( node );
	}

	/***
	 * Visit an End token, add it to our tree
	 * @param dictionary an End Token
	 */
	@Override
	public void visit(shovelsoft.btmetaparser.tokens.End end) {
		
		node = node.getParent();
	}

	/***
	 * Visit an Integer struct, add it to our tree
	 * @param integery an Integer Node
	 */
	@Override
	public void visit(shovelsoft.btmetaparser.tokens.Integer integer) throws Exception {
		
		node.addChild( new Leaf(integer, node) );
	}

	/***
	 * Visit a Data struct, add it to our tree
	 * @param data A Data Node.
	 */
	@Override
	public void visit(shovelsoft.btmetaparser.tokens.Data data) throws Exception {
		
		node.addChild( new Leaf(data, node) );
	}

}
